/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if !defined(___GRAPH2D_COLOR_H___)
#define ___GRAPH2D_COLOR_H___

#include <mana_stream.h>

namespace Graph2D
{
	class Color
	{
	public:
		float r, g, b, a;

	public:
		static Color WHITE;
		static Color BLACK;
		static Color GLAY;
		static Color CLEAR;

	public:
		Color()
		{
			set(1, 1, 1, 1);
#if 0
			asm(
				"cmoveq %1,%2,%[result]"
				: [result] "=r"(result)
				: "r" (test), "r"(new), "[result]"(old)
			);
#endif
		}

		Color(const Color& color)
		{
			r = color.r;
			g = color.g;
			b = color.b;
			a = color.a;
		}

		Color(const float r, const float g, const float b, const float a = 1)
		{
			set(r, g, b, a);
		}

		void serialize(mana_stream* stream) const
		{
			mana_stream_push_float(stream, r);
			mana_stream_push_float(stream, g);
			mana_stream_push_float(stream, b);
			mana_stream_push_float(stream, a);
		}

		void deserialize(mana_stream* stream)
		{
			r = mana_stream_pop_float(stream);
			g = mana_stream_pop_float(stream);
			b = mana_stream_pop_float(stream);
			a = mana_stream_pop_float(stream);
		}

		void identity()
		{
			set(0.0f, 0.0f, 0.0f, 1.0f);
		}

		void set(const float r, const float g, const float b, const float a = 1)
		{
			this->r = r;
			this->g = g;
			this->b = b;
			this->a = a;
		}

		Color mulRGB(const Color& color)
		{
			return mulRGB(color.r, color.g, color.b);
		}

		Color mulRGB(const float r, const float g, const float b)
		{
			return Color(this->r * r, this->g * g, this->b * b, this->a);
		}

		Color mulRGB(const float value)
		{
			return Color(this->r * value, this->g * value, this->b * value, this->a);
		}

		void setMulRGB(const Color& color)
		{
			setMulRGB(color.r, color.g, color.b);
		}

		void setMulRGB(const float r, const float g, const float b)
		{
			this->r *= r;
			this->g *= g;
			this->b *= b;
		}

		void setMulRGB(const float value)
		{
			this->r *= value;
			this->g *= value;
			this->b *= value;
		}

		Color& operator=(const Color& color)
		{
			r = color.r;
			g = color.g;
			b = color.b;
			a = color.a;
			return *this;
		}

		Color operator+(const Color& color) const
		{
			return Color(r + color.r, g + color.g, b + color.b, a + color.a);
		}

		Color operator-(const Color& color) const
		{
			return Color(r - color.r, g - color.g, b - color.b, a - color.a);
		}

		Color operator*(const Color& color) const
		{
			return Color(r * color.r, g * color.g, b * color.b, a * color.a);
		}

		Color operator/(const Color& color) const
		{
			return Color(r / color.r, g / color.g, b / color.b, a / color.a);
		}

		Color operator+(const float scalar) const
		{
			return Color(r + scalar, g + scalar, b + scalar, a + scalar);
		}

		Color operator-(const float scalar) const
		{
			return Color(r - scalar, g - scalar, b - scalar, a - scalar);
		}

		Color operator*(const float scalar) const
		{
			return Color(r * scalar, g * scalar, b * scalar, a * scalar);
		}

		Color operator/(const float scalar) const
		{
			return Color(r / scalar, g / scalar, b / scalar, a / scalar);
		}

		Color& operator+=(const Color& color)
		{
			r += color.r;
			g += color.g;
			b += color.b;
			a += color.a;
			return *this;
		}

		Color& operator-=(const Color& color)
		{
			r -= color.r;
			g -= color.g;
			b -= color.b;
			a -= color.a;
			return *this;
		}

		Color& operator*=(const Color& color)
		{
			r *= color.r;
			g *= color.g;
			b *= color.b;
			a *= color.a;
			return *this;
		}

		Color& operator/=(const Color& color)
		{
			r /= color.r;
			g /= color.g;
			b /= color.b;
			a /= color.a;
			return *this;
		}

		Color& operator+=(const float scalar)
		{
			r += scalar;
			g += scalar;
			b += scalar;
			a += scalar;
			return *this;
		}

		Color& operator-=(const float scalar)
		{
			r -= scalar;
			g -= scalar;
			b -= scalar;
			a -= scalar;
			return *this;
		}

		Color& operator*=(const float scalar)
		{
			r *= scalar;
			g *= scalar;
			b *= scalar;
			a *= scalar;
			return *this;
		}

		Color& operator/=(const float scalar)
		{
			r /= scalar;
			g /= scalar;
			b /= scalar;
			a /= scalar;
			return *this;
		}

		bool operator==(const Color& color) const
		{
			return(r == color.r && g == color.g && b == color.b && a == color.a);
		}

		bool operator!=(const Color& color) const
		{
			return(r != color.r || g != color.g || b != color.b || a != color.a);
		}

		float operator[](const int index)
		{
			return static_cast<float*>(&r)[index];
		}

		float operator[](const int index) const
		{
			return static_cast<const float*>(&r)[index];
		}

		operator float*()
		{
			return &r;
		}

		operator const float*() const
		{
			return &r;
		}
	};
}

#endif
